In my two previous blog posts I have introduced Ratpack and the lightweight ODM layer available in our Java SDK. This post will build up on them and showcase a REST API to manage users through the Couchbase repository.

I want my API to support the four basic HTTP verbs and to support content-type. Everything has been thought out for that in Ratpack. The Chain object is like a builder for composing handlers. So I wrote a new Action class to bind a chain to the 'user' URL prefix. This will simplify my main method a lot:

To make sure my UserHandler instance can be found, I also need to add it to my Config Guice module:

I also add the UserRenderer class that will be used to handle the different content-types.

Custom Renderer

In Ratpack you can register new RendererSupport classes. Their goal is to specify a way to render your T object based on the Context. In my case I want to render a User object based on the context content-type. The Context object gives you a byContent method that allows to compose rendering based on the content-type set in the request. Usual types are predefined already. In my case I just want to support json and text:

The text rendering is just a simple toString(). The JSON version uses the Jackson object available by default in Ratpack. It gives you access to shortcut for JSON/Object conversions. A call to the json method giving the User object as argument will do. Jackson is also used internally by our Java SDK. But there is a trick. The @Field annotation I used for my Couchabse ODM is not picked up by the default Jackson mapper used in Ratpack. So I need to add the Jackson @JsonProperty annotation to compensate. I would not have had to add anything if I did not use the @Field annotation in the first place. I will try to find a better way to make this work but in the meantime it works just fine.

Composing the API with Handlers

I am now in a good position to start working on the API. GET, PUT and DELETE need a user id to work. So the first thing I am doing is checking if there is something after the /user/ URL. Handlers are all chained together and executed in the order you declare them. Once you get in a handler, the chain stops. So you want to make sure you declare /user/:userId before /user/. Path binding uses regex, you'll find examples in the Chain documentation.

Calling the path method allow me to give the path regex and a handler as argument. In the Handler I start by getting the Couchbase repository and the userId from the path tokens. Then I call the byMethod method to define a function for each HTTP verb I need to support. Here I will return a user for GET, update or create a user for PUT and remove the user for REMOVE.

The most interesting verb here is PUT as it requires content form the request. The Context parse method takes a Parse object as argument and returns a Promise. Here I want to parse the JSON from the request and map it to a User object. So it returns a Promise. Since I am an RxJava user I will map that Promise to an Observable, then map the User object to an EntityDocument to finally save it with the Couchbase repository. Than I convert that observable back to a ratpack promise and send back a simple OK string. You might want to do something smarter in real life se cases 🙂

Once the HTTP verbs that needs a userId are implemented, I can finish with all the others. And I can do that easily with the method all. Here I get the repository and the bucket from the registry. Then for the GET method, since it has no user id, I return the full list of Users. To do so I run a basic N1QL query. Finally the POST is identical to the PUT method.

This may not be a totally RESTFUL API, but should give you a good idea on how easy it is to craft one with Ratpack, Couchbase and RxJava. Please let me know if you want to see more stuff happening around Ratpack, like a Couchbase Module.

Author

Spread the love

Author

Posted by james.oquendo

Couchbase team member

Leave a reply